﻿#include "ssTime.h"
#ifdef _WIN32
#include <Windows.h>
#endif
#include "../string/ssStrfunc.h"
#ifdef __cplusplus
#include <chrono>
#endif


namespace StarSeeker
{
	time_t ssTime::s_sysStart = ::time(NULL);
	time_t ssTime::s_timeZone = 28800;
	time_t ssTime::s_systemZone = ssTime::GetSystemTimeZone();
	time_t ssTime::s_timeOffset = 0;

void ssYMDHMS::Zero()
{
	year.i32p = month.i32p = day.i32p = hour.i32p = minute.i32p = second.i32p = wday.i32p = yday.i32p = 0;
}

bool ssYMDHMS::IsZero()
{
	return year.i32p == 0 && month.i32p == 0 && day.i32p == 0
		&& hour.i32p == 0 && minute.i32p == 0 && second.i32p == 0 
		&& wday.i32p == 0 && yday.i32p == 0;
}

void ssYMDHMS::GetLocalTime(char* buf)
{
	snprintf(buf, SS_TIME_STR_LEN, "%d-%d-%d %d:%d:%d", year.i32p, month.i32p, day.i32p, hour.i32p, minute.i32p, second.i32p);
}

ST64_u ssYMDHMS::GetTimestamp()
{
	ST64_u ret;
	ret.i64p = 0;
	if (IsZero()) return ret;
	ret.i64p = ssTime::GetTimestamp(*this);
	return ret;
}

ST64_u ssTime::GetTimeNow()
{
	ST64_u t;
	t.i64p = ::time(NULL) + ssTime::s_timeOffset;
	return t;
}

ST64_u ssTime::GetTimeNowMS()
{
	ST64_u t;
#ifdef __cplusplus
	t.i64p = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
#else
#ifdef _WIN32
	static u64 timeStamp = 0;
	if (timeStamp <= 0)
	{
		timeStamp = (time(NULL) - GetTickCount() / 1000) * 1000;
	}
	t.u64p = timeStamp + GetTickCount();
#else
	struct timeval tv;
	gettimeofday(&tv, NULL);
	t.i64p = tv.tv_sec * 1000;
	t.i64p += tv.tv_usec / 1000;
#endif
#endif
	t.i64p += ssTime::s_timeOffset*1000;
	return t;
}

tm* ssTime::GetTime()
{
	time_t now = GetTimeNow().i64p;
	return ::gmtime(&now);
}

tm* ssTime::GetTime(time_t timestamp)
{
	return ::gmtime(&timestamp);
}

void ssTime::GetTime(ssYMDHMS& t)
{
	tm* ti = GetTime();
	t.year.i32p = ti->tm_year + 1900;
	t.month.i32p = ti->tm_mon + 1;
	t.day.i32p = ti->tm_mday;
	t.hour.i32p = ti->tm_hour;
	t.minute.i32p = ti->tm_min;
	t.second.i32p = ti->tm_sec;
	t.wday.i32p = ti->tm_wday;
	t.yday.i32p = ti->tm_yday;
}

void ssTime::GetTime(time_t timestamp, ssYMDHMS& out)
{
	tm* ti = gmtime(&timestamp);
	out.year.i32p = ti->tm_year + 1900;
	out.month.i32p = ti->tm_mon + 1;
	out.day.i32p = ti->tm_mday;
	out.hour.i32p = ti->tm_hour;
	out.minute.i32p = ti->tm_min;
	out.second.i32p = ti->tm_sec;
	out.wday.i32p = ti->tm_wday;
	out.yday.i32p = ti->tm_yday;
}

time_t ssTime::GetTimestamp(ssYMDHMS& t)
{
	tm t2 = { 0 };
	t2.tm_year = t.year.i32p-1900;
	t2.tm_mon = t.month.i32p - 1;
	t2.tm_mday = t.day.i32p;
	t2.tm_hour = t.hour.i32p;
	t2.tm_min = t.minute.i32p;
	t2.tm_sec = t.second.i32p;
	return ::mktime(&t2);
}

void ssTime::GetLocalTime(char* buf)
{
	tm* ti = GetLocalTime();
	snprintf(buf, SS_TIME_STR_LEN, "%d-%d-%d %d:%d:%d", ti->tm_year + 1900, ti->tm_mon + 1, ti->tm_mday, ti->tm_hour, ti->tm_min, ti->tm_sec);
}

tm* ssTime::GetLocalTime()
{
	time_t now = GetTimeNow().i64p + ssTime::s_timeZone;
	return ::gmtime(&now);
}

tm * ssTime::GetLocalTime(time_t timestamp)
{
	timestamp += ssTime::s_timeZone;
	return ::gmtime(&timestamp);
}

void ssTime::GetLocalTime(ssYMDHMS& t)
{
	tm* ti = GetLocalTime();
	t.year.i32p = ti->tm_year + 1900;
	t.month.i32p = ti->tm_mon + 1;
	t.day.i32p = ti->tm_mday;
	t.hour.i32p = ti->tm_hour;
	t.minute.i32p = ti->tm_min;
	t.second.i32p = ti->tm_sec;
	t.wday.i32p = ti->tm_wday;
	t.yday.i32p = ti->tm_yday;
}

void ssTime::GetLocalTime(time_t timestamp, ssYMDHMS& out)
{
	timestamp += ssTime::s_timeZone;
	tm* ti = gmtime(&timestamp);
	out.year.i32p = ti->tm_year+1900;
	out.month.i32p = ti->tm_mon+1;
	out.day.i32p = ti->tm_mday;
	out.hour.i32p = ti->tm_hour;
	out.minute.i32p = ti->tm_min;
	out.second.i32p = ti->tm_sec;
	out.wday.i32p = ti->tm_wday;
	out.yday.i32p = ti->tm_yday;
}

//time_t ssTime::GetLocalTimestamp(ssYMDHMS& t)
//{
//	return GetTimestamp(t) - ssTime::s_systemZone + ssTime::s_timeZone;
//}

void ssTime::GetLocalTimeYMD( char* buf )
{
	tm* ti = GetLocalTime();
	snprintf(buf, SS_TIME_STR_LEN, "%d-%d-%d",ti->tm_year+1900,ti->tm_mon+1,ti->tm_mday);
}

void ssTime::GetLocalTimeYMDH( char* buf )
{
	tm* ti = GetLocalTime();
	snprintf(buf, SS_TIME_STR_LEN, "%d-%d-%d.%d",ti->tm_year+1900,ti->tm_mon+1,ti->tm_mday,ti->tm_hour);
}

void ssTime::GetLocalTimeHMS( char* buf )
{
	tm* ti = GetLocalTime();
	snprintf(buf, SS_TIME_STR_LEN, "%d:%d:%d",ti->tm_hour,ti->tm_min,ti->tm_sec);
}

ST32_u ssTime::GetDateNum(bool localTime)
{
	tm* ti = localTime?GetLocalTime():GetTime();
	ST32_u n;
	n.i32p = (ti->tm_year+1900)*10000 + (ti->tm_mon+1)*100 + ti->tm_mday;
	return n;
}

ST32_u ssTime::GetTimeNum(bool localTime)
{
	tm* ti = localTime ? GetLocalTime() : GetTime();
	ST32_u n;
	n.i32p = ti->tm_hour * 10000 + ti->tm_min * 100 + ti->tm_sec;
	return n;
}

void ssTime::SetTimeZone(time_t zone)
{
	ssTime::s_timeZone = zone;
}

ST64_u ssTime::GetDayZero(time_t timestamp)
{
	ST64_u dayZero;
	dayZero.i64p = timestamp - ((timestamp + ssTime::s_timeZone) % 86400);
	return dayZero;
}

ST64_u ssTime::GetTodayZero()
{
	time_t now = GetTimeNow().i64p;
	return GetDayZero(now);
}

StarSeeker::i32 ssTime::GetDayDiff(time_t timestamp1, time_t timestamp2)
{
	ST64_u d1 = GetDayZero(timestamp1);
	ST64_u d2 = GetDayZero(timestamp2);
	return i32(d2.i64p - d1.i64p);
}

i32 ssTime::GetDayDiff(time_t last, time_t now, i32 secondOfDay)
{
	//防止负数
	u32 dayslast = ssTime::GetDays(last - secondOfDay + 86400);
	u32 daysnow = ssTime::GetDays(now - secondOfDay + 86400);
	return daysnow - dayslast;
}

time_t ssTime::GetStart()
{
	return s_sysStart;
}

u32 ssTime::GetDays(time_t timestamp)
{
	return (u32)(timestamp + ssTime::s_timeZone) / 86400;
}
u32 ssTime::GetWeeks(time_t timestamp)
{ 
	//1970年1月1日是星期四
	return(GetDays(timestamp) + 3) / 7;
}

time_t ssTime::GetMonday(time_t timestamp)
{
	return ((GetWeeks(timestamp) * 7) - 3) * 86400 - ssTime::s_timeZone;
}

time_t ssTime::GetSystemTimeZone()
{
#ifdef _WIN32
	long tz = 0;
	::_get_timezone(&tz);
	return (time_t)tz;
#else
	time_t timestamp = time(0);
	tm *timeinfo = localtime(&timestamp);
	return (time_t)timeinfo->tm_gmtoff;
#endif
}

time_t ssTime::GetWeekDayTime(time_t timestamp, i32 weekday, i32 secondOfDay)
{
	//if (weekday < 1 || weekday > 7)
	//	return 0;
	time_t mondayTm = GetMonday(timestamp);
	return mondayTm + (weekday - 1) * 86400 + secondOfDay;
}

ssYMDHMS ssTime::StringToTimeStruct(const char * str, const char * format)
{
	ssYMDHMS timeInfo = {0};
	int year, month, day, hour, minute, second;
	if (str && format)
	{
		::sscanf(str, format, &year, &month, &day, &hour, &minute, &second);
		timeInfo.year.i32p = year;
		timeInfo.month.i32p = month;
		timeInfo.day.i32p = day;
		timeInfo.hour.i32p = hour;
		timeInfo.minute.i32p = minute;
		timeInfo.second.i32p = second;
	}
	return timeInfo;
}

void ssTime::SetTimeOffset(time_t offset)
{
	ssTime::s_timeOffset = offset;
}

time_t ssTime::SetTimeOffset(ssYMDHMS & offset)
{
	i64 now = ::time(NULL);
	ssTime::s_timeOffset = offset.GetTimestamp().i64p - now;
	return ssTime::s_timeOffset;
}

time_t ssTime::SetTimeOffset(const char * str)
{
	if (0==str || 0==::strlen(str))
	{
		ssTime::s_timeOffset = 0;
		return 0;
	}
	else
	{
		ssYMDHMS st = StringToTimeStruct(str);
		return SetTimeOffset(st);
	}
}

}
